import pandas as pd
import plotly.express as px
from nicegui import ui, app
import os
import analysis  # 自定义分析模块

# 全局变量
df = None
area_select = None
min_price_slider = None
max_price_slider = None
chart_select = None
plot_container = None


# 数据加载函数
def load_and_clean_data():
    global df
    raw_path = 'data/AB_NYC_2019.csv'
    clean_path = 'data/cleaned_airbnb.csv'

    # 如果清洗后的数据已存在，直接加载
    if os.path.exists(clean_path):
        df = pd.read_csv(clean_path)
        ui.notify("数据加载成功！", type='positive')
        return True

    # 加载原始数据
    if not os.path.exists(raw_path):
        ui.notify("原始数据文件不存在，请下载数据集并放在data目录下", type='negative')
        return False

    try:
        df = pd.read_csv(raw_path)

        # 数据清洗
        # 1. 处理缺失值
        df.fillna({
            'name': 'Unknown',
            'host_name': 'Unknown',
            'last_review': 'No Review',
            'reviews_per_month': 0
        }, inplace=True)

        # 2. 移除不必要的列
        df.drop(['id', 'host_id'], axis=1, inplace=True)

        # 3. 处理异常值：移除价格过高或为0的房源
        df = df[(df['price'] > 0) & (df['price'] < 1000)]

        # 4. 创建新特征：每平方英尺价格
        df['price_per_sqft'] = df['price'] / df['minimum_nights']
        df['price_per_sqft'] = df['price_per_sqft'].replace([float('inf'), -float('inf')], 0)

        # 5. 分类转换
        df['room_type'] = pd.Categorical(df['room_type'])

        # 保存清洗后的数据
        df.to_csv(clean_path, index=False)
        ui.notify("数据清洗完成并已保存", type='positive')
        return True
    except Exception as e:
        ui.notify(f"数据处理错误: {str(e)}", type='negative')
        return False


# 初始化UI组件
def init_ui_components():
    global area_select, min_price_slider, max_price_slider, chart_select

    # 行政区选择
    areas = ['全部区域'] + sorted(df['neighbourhood_group'].unique().tolist())
    area_select = ui.select(
        options=areas,
        value='全部区域',
        label='选择行政区'
    ).classes('mb-4')

    # 价格范围滑块
    ui.label('价格范围 (美元)').classes('mt-4 mb-2')
    min_price_slider = ui.slider(min=0, max=500, value=0).classes('w-full')
    max_price_slider = ui.slider(min=0, max=500, value=500).classes('w-full')

    # 图表类型选择
    chart_types = [
        '价格分布直方图',
        '房间类型分布图',
        '纽约房源分布地图',
        '行政区价格对比'
    ]
    chart_select = ui.select(
        options=chart_types,
        value='价格分布直方图',
        label='选择图表类型'
    ).classes('mb-6')


# 创建UI界面
def create_ui():
    global plot_container

    # 标题区域
    with ui.header().classes('bg-blue-600 text-white p-4 shadow-md'):
        with ui.row().classes('items-center'):
            ui.icon('airbnb', size='lg').classes('mr-2')
            ui.label('纽约Airbnb数据分析平台').classes('text-2xl font-bold')

    # 主内容区
    with ui.row().classes('w-full h-full'):
        # 控制面板
        with ui.column().classes('w-1/4 bg-gray-100 p-6 h-full border-r'):
            ui.label('数据控制面板').classes('text-xl font-bold mb-4')

            # 加载数据按钮
            ui.button('加载并清洗数据', on_click=on_load_data).classes('mb-4 w-full bg-green-600 text-white')

            # 当数据加载完成后初始化UI组件
            if df is not None:
                init_ui_components()

                # 筛选按钮
                ui.button('应用筛选', on_click=update_visualization).classes('w-full bg-blue-600 text-white')

            # 数据摘要
            if df is not None:
                with ui.expansion('数据摘要', icon='info').classes('mt-6 w-full'):
                    ui.label(f'数据集包含 {len(df)} 条记录')
                    ui.label(f'包含 {len(df["neighbourhood_group"].unique())} 个行政区')
                    ui.label(f'平均价格: ${df["price"].mean():.2f}')
                    ui.label(f'房源类型: {len(df["room_type"].unique())} 种')

        # 可视化区域
        with ui.column().classes('w-3/4 p-6 h-full'):
            plot_container = ui.column().classes('w-full h-full')

            # 如果没有数据，显示提示信息
            if df is None:
                with plot_container:
                    ui.label("请先点击'加载并清洗数据'按钮加载数据").classes('text-lg text-gray-500')

            # 数据表格
            if df is not None:
                with ui.expansion('查看原始数据', icon='table_chart').classes('mt-4 w-full'):
                    ui.table.from_pandas(df.head(50)).classes('max-h-96')

    # 页脚
    with ui.footer().classes('bg-gray-800 text-white p-4 text-center'):
        ui.label('© 2023 纽约Airbnb数据分析项目 | 基于Kaggle数据集').classes('text-sm')


# 加载数据按钮回调
def on_load_data():
    if load_and_clean_data():
        # 重新初始化UI组件
        init_ui_components()
        # 添加应用筛选按钮
        with ui.element('div').classes('w-full'):
            ui.button('应用筛选', on_click=update_visualization).classes('w-full bg-blue-600 text-white')
        update_visualization()


# 更新可视化
def update_visualization():
    if df is None:
        ui.notify("请先加载数据", type='warning')
        return

    # 获取筛选条件
    selected_area = area_select.value if area_select else '全部区域'
    min_price = min_price_slider.value if min_price_slider else 0
    max_price = max_price_slider.value if max_price_slider else 500
    chart_type = chart_select.value if chart_select else '价格分布直方图'

    # 将中文转换为英文标识符
    chart_mapping = {
        '价格分布直方图': 'price_distribution',
        '房间类型分布图': 'room_type_distribution',
        '纽约房源分布地图': 'availability_map',
        '行政区价格对比': 'neighbourhood_comparison'
    }
    chart_key = chart_mapping.get(chart_type, 'price_distribution')

    # 将"全部区域"转换为实际筛选值
    if selected_area == '全部区域':
        filtered_df = df.copy()
    else:
        filtered_df = df[df['neighbourhood_group'] == selected_area]

    # 应用价格筛选
    filtered_df = filtered_df[(filtered_df['price'] >= min_price) &
                              (filtered_df['price'] <= max_price)]

    # 创建图表
    try:
        if chart_key == 'price_distribution':
            fig = analysis.create_price_distribution(filtered_df, selected_area)
        elif chart_key == 'room_type_distribution':
            fig = analysis.create_room_type_distribution(filtered_df, selected_area)
        elif chart_key == 'availability_map':
            fig = analysis.create_nyc_map(filtered_df, selected_area)
        elif chart_key == 'neighbourhood_comparison':
            fig = analysis.create_neighborhood_comparison(filtered_df)
        else:
            fig = analysis.create_price_distribution(filtered_df, selected_area)

        # 更新可视化容器
        plot_container.clear()
        with plot_container:
            ui.plotly(fig).classes('w-full h-full')
    except Exception as e:
        ui.notify(f"图表生成错误: {str(e)}", type='negative')


# 启动应用
if __name__ in {"__main__", "__mp_main__"}:
    app.on_exception(lambda e: ui.notify(f'错误: {e}', type='negative'))
    create_ui()
    ui.run(title='Airbnb数据分析', port=8080, reload=False)